﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;

namespace SpriteAtlasRuntime
{
    public class AnimationScript
    {
        private AnimationCollection mParent;
        private byte[] mScript;
        private MemoryStream mStream;
        private BinaryReader mReader;

        private int mCurCommand;
        private float mTimeRemaining;

        private ISpriteComponent mSpriteComponent;
        private IModelComponent mModelComponent;

        private Dictionary<string, long> mLabels;

        internal ScriptCommands CurCommand
        {
            get { return (ScriptCommands)mCurCommand; }
        }

        internal float TimeRemaining
        {
            get { return mTimeRemaining; }
            set { mTimeRemaining = value; }
        }

        internal ISpriteComponent SpriteTarget
        {
            get { return mSpriteComponent; }
        }

        internal IModelComponent ModelTarget
        {
            get { return mModelComponent; }
        }

        internal void ReadNextCommand()
        {
            mCurCommand = mReader.ReadInt32();
            Debug.Assert(Enum.IsDefined(typeof(ScriptCommands), mCurCommand) || mCurCommand == (int)ScriptCommands.End - 1);
        }

        internal ScriptTargets ReadNextTarget()
        {
            ScriptTargets target = (ScriptTargets)mReader.ReadInt32();
            Debug.Assert(Enum.IsDefined(typeof(ScriptTargets), target));
            return target;
        }

        internal void ReadThisCommandTime()
        {
            mTimeRemaining = (float)mReader.ReadSingle();
        }

        internal int ReadNextInt()
        {
            return mReader.ReadInt32();
        }

        internal float ReadNextFloat()
        {
            return mReader.ReadSingle();
        }

        internal string ReadNextString()
        {
            return mReader.ReadString();
        }

        internal bool ReadNextBool()
        {
            return mReader.ReadBoolean();
        }

        internal void SkipBytes(int skipBytes)
        {
            mReader.ReadBytes(skipBytes);
        }

        internal void SaveLabel(string labelName)
        {
            Debug.Assert(!mLabels.ContainsKey(labelName));
            mLabels.Add(labelName, mStream.Position);
        }

        internal void GotoLabel(string labelName)
        {
            Debug.Assert(mLabels.ContainsKey(labelName));
            mStream.Position = mLabels[labelName];
        }

        internal void SetScript(int newScriptId)
        {
            mStream.Dispose();
            mReader.Dispose();

            mScript = mParent[newScriptId];
            mStream = new MemoryStream(mScript);
            mReader = new BinaryReader(mStream);

            mLabels.Clear();
            mTimeRemaining = 0;
        }

        internal AnimationScript(AnimationCollection parent, int index, ISpriteComponent animated, IModelComponent model)
        {
            mParent = parent;
            mScript = parent[index];
            mStream = new MemoryStream(mScript);
            mReader = new BinaryReader(mStream);

            mSpriteComponent = animated;
            mModelComponent = model;

            mLabels = new Dictionary<string, long>();

            mTimeRemaining = 0;

            ReadNextCommand();
        }
    }
}
